home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ms_sh21s.zip / SH210 / SRC / GLOB.C < prev    next >
C/C++ Source or Header  |  1992-09-04  |  15KB  |  641 lines

  1. /* MS-DOS GLOB (3C) FUNCTION
  2.  *
  3.  * MS-DOS GLOB FUNCTION - Copyright (c) 1990,1,2 Data Logic Limited.
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form.
  10.  *
  11.  *    $Header: /usr/users/istewart/src/shell/sh2.1/RCS/glob.c,v 2.0 1992/04/13 17:39:09 Ian_Stewartson Exp $
  12.  *
  13.  *    $Log: glob.c,v $
  14.  * Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  15.  * MS-Shell 2.0 Baseline release
  16.  *
  17.  */
  18.  
  19. #include <sys/types.h>            /* MS-DOS type definitions      */
  20. #include <sys/stat.h>            /* File status definitions    */
  21. #include <stdio.h>            /* Standard I/O delarations     */
  22. #include <stdlib.h>            /* Standard library functions   */
  23. #include <string.h>            /* String library functions     */
  24. #include <limits.h>            /* String library functions     */
  25. #include <dirent.h>            /* Direction I/O functions    */
  26. #include <ctype.h>            /* Character types function    */
  27. #include <unistd.h>            /* Other functions        */
  28. #include <malloc.h>            /* Malloc functions        */
  29. #include <glob.h>
  30. #ifdef MSDOS
  31. #ifdef OS2
  32. #define INCL_DOSDEVICES
  33. #include <os2.h>            /* OS2 functions declarations       */
  34. #else
  35. #include <bios.h>            /* DOS BIOS functions        */
  36. #include <dos.h>            /* DOS functions        */
  37. #endif
  38. #endif
  39.  
  40. static int    _GP_SortCompare        _PROTO ((char **, char **));
  41. static int    _GP_ExpandField        _PROTO ((char *, char *, glob_t *));
  42. static int    _GP_ExpandMetaCharacters _PROTO ((char *, glob_t *));
  43. static int    _GP_AddArgument        _PROTO ((char *, glob_t *));
  44. static bool    _GP_MatchPattern    _PROTO ((char *, char *));
  45.  
  46. static char    *_GP_MetaChars = "?*[\\";
  47. static char    *_GP_NullString = "";
  48.  
  49. #ifdef MSDOS
  50. static    int    _GP_GetNumberofFloppyDrives (void);
  51.  
  52. #ifdef OS2
  53. static void     _dos_setdrive (unsigned int, unsigned int *);
  54. static void     _dos_getdrive (unsigned int *);
  55. #endif
  56.  
  57. static char    *_GP_CheckForMultipleDrives    _PROTO ((char *));
  58. #endif
  59.  
  60.  
  61. /* Free up space */
  62.  
  63. void    globfree (gp)
  64. glob_t    *gp;
  65. {
  66.     int        i = (gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0;
  67.  
  68.     while (i < gp->gl_pathc)
  69.     free (gp->gl_pathv[i++]);
  70.  
  71.     free (gp->gl_pathv);
  72. }
  73.  
  74. /* Main search function */
  75.  
  76. int    glob (Pattern, flags, ErrorFunction, gp)
  77. char    *Pattern;
  78. int    flags;
  79. int    (*ErrorFunction) _PROTO ((char *, int));
  80. glob_t    *gp;
  81. {
  82.     int        ReturnValue;
  83.     char    *PatternCopy;
  84.     char    *cp;
  85.  
  86. /* If no append mode - initialise */
  87.  
  88.     if (!(flags & GLOB_APPEND))
  89.     {
  90.     gp->gl_pathc = 0;
  91.     gp->gl_pathv = (char **)NULL;
  92.     }
  93.  
  94.     gp->gl_flags = flags;
  95.     gp->gl_ef = ErrorFunction;
  96.  
  97.     if ((PatternCopy = alloca (strlen (Pattern) + 1)) == (char *)NULL)
  98.     return GLOB_NOSPACE;
  99.  
  100. /* Expand and kill environment */
  101.  
  102.     if (ReturnValue = _GP_ExpandMetaCharacters (strcpy (PatternCopy, Pattern),
  103.                         gp))
  104.     return ReturnValue;
  105.  
  106. /* Check for no finds.  If add value, strip out \ from the string */
  107.  
  108.     if ((gp->gl_pathc == 0) && (flags & GLOB_NOCHECK))
  109.     {
  110.     cp = strcpy (PatternCopy, Pattern);
  111.  
  112.     while ((cp = strpbrk (cp, "?*[")) != (char *)NULL)
  113.     {
  114.         if ((cp == PatternCopy) || (*(cp - 1) != '\\'))
  115.         cp++;
  116.  
  117.         else
  118.         memmove (cp - 1, cp, strlen (cp) + 1);
  119.     }
  120.  
  121.     if (ReturnValue = _GP_AddArgument (PatternCopy, gp))
  122.         return ReturnValue;
  123.     }
  124.  
  125. /* Terminate string */
  126.  
  127.     if ((gp->gl_pathc != 0) && (ReturnValue = _GP_AddArgument ((char *)NULL, gp)))
  128.     return ReturnValue;
  129.  
  130. /* Get the sort length */
  131.  
  132.     ReturnValue = (gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0;
  133.  
  134.     if ((!(flags & GLOB_NOSORT)) && (gp->gl_pathc > 1))
  135.     qsort (&gp->gl_pathv[ReturnValue], gp->gl_pathc, sizeof (char *),
  136.         _GP_SortCompare);
  137.  
  138.     return 0;
  139. }
  140.  
  141. /* Compare function for sort */
  142.  
  143. static int    _GP_SortCompare (a1, a2)
  144. char        **a1, **a2;
  145. {
  146.     return strcmp (*a1, *a2);
  147. }
  148.  
  149. /* Expand a field if it has metacharacters in it */
  150.  
  151. static int    _GP_ExpandField (CurrentDirectoryPattern, AppendString, gp)
  152. char        *CurrentDirectoryPattern;    /* Prefix field        */
  153. char        *AppendString;            /* Postfix field        */
  154. glob_t        *gp;
  155. {
  156.     int         i;
  157.     int            ReturnValue = 0;    /* Return Value        */
  158.     char        *FullFileName;        /* Search file name    */
  159.     char        *FileNameStart;
  160.     char        *MatchString;        /* Match string        */
  161.     DIR            *DirHandler;
  162.     struct dirent    *CurrentDirectoryEntry;
  163. #ifdef MSDOS
  164.     unsigned int    CurrentDrive;        /* Current drive    */
  165.     unsigned int    MaxDrives;        /* Max drive        */
  166.     unsigned int    SelectedDrive;        /* Selected drive    */
  167.     unsigned int    x_drive, y_drive;    /* Dummies        */
  168.     char        *DriveCharacter;    /* Multi-drive flag    */
  169.     char        SDriveString[2];
  170.  
  171. /* Convert file name to lower case */
  172.  
  173. #ifndef OS2
  174.     strlwr (CurrentDirectoryPattern);
  175. #else
  176.     if (!IsHPFSFileSystem (CurrentDirectoryPattern))
  177.     strlwr (CurrentDirectoryPattern);
  178. #endif
  179.  
  180. /* Search all drives ? */
  181.  
  182.     if ((DriveCharacter = _GP_CheckForMultipleDrives (CurrentDirectoryPattern))
  183.         != (char *)NULL)
  184.     {
  185.     _dos_getdrive (&CurrentDrive);    /* Get number of drives        */
  186.     _dos_setdrive (CurrentDrive, &MaxDrives);
  187.     SDriveString[1] = 0;
  188.  
  189.     for (SelectedDrive = 1; SelectedDrive <= MaxDrives; ++SelectedDrive)
  190.     {
  191.         _dos_setdrive (SelectedDrive, &x_drive);
  192.         _dos_getdrive (&y_drive);
  193.         _dos_setdrive (CurrentDrive, &x_drive);
  194.  
  195. /* Check to see if the second diskette drive is really there */
  196.  
  197.         if ((_GP_GetNumberofFloppyDrives () < 2) && (SelectedDrive == 2))
  198.         continue;
  199.  
  200. /* If the drive exists and is in our list - process it */
  201.  
  202.         *DriveCharacter = 0;
  203.         *SDriveString = (char)(SelectedDrive + 'a' - 1);
  204.         strlwr (CurrentDirectoryPattern);
  205.  
  206.         if ((y_drive == SelectedDrive) &&
  207.         _GP_MatchPattern (SDriveString, CurrentDirectoryPattern))
  208.         {
  209.         if ((FullFileName = alloca (strlen (DriveCharacter) + 3))
  210.                 == (char *)NULL)
  211.             return GLOB_NOSPACE;
  212.  
  213.         *DriveCharacter = ':';
  214.         *FullFileName = *SDriveString;
  215.         strcpy (FullFileName + 1, DriveCharacter);
  216.  
  217.         if (i = _GP_ExpandField (FullFileName, AppendString, gp))
  218.             return i;
  219.         }
  220.  
  221.         *DriveCharacter = ':';
  222.     }
  223.  
  224.     return 0;
  225.     }
  226. #endif
  227.  
  228. /* Get the path length */
  229.  
  230.     MatchString = strrchr (CurrentDirectoryPattern, '/');
  231. #ifdef MSDOS
  232.     if ((MatchString == (char *)NULL) &&
  233.     (*(CurrentDirectoryPattern + 1) == ':'))
  234.     MatchString = CurrentDirectoryPattern + 1;
  235. #endif
  236.  
  237. /* Set up file name for search */
  238.  
  239.     if ((MatchString == (char *)NULL) || (*MatchString == ':'))
  240.     {
  241.     if ((FullFileName = alloca (NAME_MAX + 7 +
  242.                     strlen (AppendString))) == (char *)NULL)
  243.         return GLOB_NOSPACE;
  244.  
  245.     if (MatchString != (char *)NULL)
  246.         *(strcpy (FullFileName, "x:.")) = *CurrentDirectoryPattern;
  247.  
  248.     else
  249.         strcpy (FullFileName, ".");
  250.  
  251.     FileNameStart = FullFileName +
  252.             (int)((MatchString != (char *)NULL) ? 2 : 0);
  253.     }
  254.  
  255. /* Case of /<directory>/... */
  256.  
  257.     else if ((FullFileName = alloca (NAME_MAX + 4 + strlen (AppendString) +
  258.                 (i = (int)(MatchString - CurrentDirectoryPattern))))
  259.             == (char *)NULL)
  260.         return GLOB_NOSPACE;
  261.  
  262.     else
  263.     {
  264.     strncpy (FullFileName, CurrentDirectoryPattern, i);
  265.     *((FileNameStart = FullFileName + i)) = 0;
  266.     strcpy (FileNameStart++, "/");
  267.     }
  268.  
  269.     MatchString = (MatchString == (char *)NULL) ? CurrentDirectoryPattern
  270.                         : MatchString + 1;
  271.  
  272. /* Search for file names */
  273.  
  274.     if ((DirHandler = opendir (FullFileName)) == (DIR *)NULL)
  275.     {
  276.     i = 0;
  277.  
  278.     if (((gp->gl_ef != NULL) && (*gp->gl_ef)(FullFileName, errno)) ||
  279.         (gp->gl_flags & GLOB_ERR))
  280.         i = GLOB_ABEND;
  281.  
  282.     return i;
  283.     }
  284.  
  285. /* Are there any matches */
  286.  
  287.     while ((CurrentDirectoryEntry = readdir (DirHandler)) !=
  288.         (struct dirent *)NULL)
  289.     {
  290.     if ((*CurrentDirectoryEntry->d_name == '.') && (*MatchString != '.'))
  291.         continue;
  292.  
  293. /* Check for match */
  294.  
  295.     if (_GP_MatchPattern (CurrentDirectoryEntry->d_name, MatchString))
  296.     {
  297.         strcpy (FileNameStart, CurrentDirectoryEntry->d_name);
  298.  
  299. /* If the postfix is not null, this must be a directory */
  300.  
  301.         if (strlen (AppendString))
  302.         {
  303.         struct stat        statb;
  304.         char            *p;
  305.  
  306. /* If not a directory - go to the next file */
  307.  
  308.         if (stat (FullFileName, &statb) < 0 ||
  309.             !S_ISDIR (statb.st_mode & S_IFMT))
  310.             continue;
  311.  
  312. /* Are there any metacharacters in the postfix? */
  313.  
  314.         if ((p = strpbrk (AppendString, _GP_MetaChars)) == (char *)NULL)
  315.         {
  316.  
  317. /* No - build the file name and check it exists */
  318.  
  319.             strcat (strcat (FileNameStart, "/"), AppendString);
  320.  
  321.             if ((access (FullFileName, F_OK) == 0) &&
  322.             (ReturnValue = _GP_AddArgument (FullFileName, gp)))
  323.             break;
  324.         }
  325.  
  326. /* Yes - build the filename upto the start of the meta characters */
  327.  
  328.         else
  329.         {
  330.             if ((p = strchr (p, '/')) != (char *)NULL)
  331.             *(p++) = 0;
  332.  
  333.             else
  334.             p = _GP_NullString;
  335.  
  336. /* Build the new directory name and check it out */
  337.  
  338.             strcat (strcat (FileNameStart, "/"), AppendString);
  339.             ReturnValue = _GP_ExpandField (FullFileName, p, gp);
  340.  
  341.             if (p != _GP_NullString)
  342.                *(--p) = '/';
  343.  
  344. /* Check for errors */
  345.  
  346.             if (ReturnValue)
  347.             break;
  348.         }
  349.         }
  350.  
  351. /* Process this file.  If error - terminate */
  352.  
  353.         else if ((access (FullFileName, F_OK) == 0) &&
  354.              (ReturnValue = _GP_AddArgument (FullFileName, gp)))
  355.         break;
  356.     }
  357.     }
  358.  
  359.     closedir (DirHandler);
  360.     return ReturnValue;
  361. }
  362.  
  363. /* Find the location of meta-characters.  If no meta, add the argument and
  364.  * return.  If meta characters, expand directory containing meta characters.
  365.  */
  366.  
  367. static int    _GP_ExpandMetaCharacters (file, gp)
  368. char        *file;
  369. glob_t        *gp;
  370. {
  371.     char    *p;
  372.     int        ReturnValue;
  373.  
  374. /* No metas - add to string */
  375.  
  376.     if ((p = strpbrk (file, _GP_MetaChars)) == (char *)NULL)
  377.     {
  378.     if (access (file, F_OK) < 0)
  379.         return 0;
  380.  
  381.     return _GP_AddArgument (file, gp);
  382.     }
  383.  
  384. /* Ok - metas, find the end of the start of the directory */
  385.  
  386.     else if ((p = strchr (p, '/')) != (char *)NULL)
  387.     *(p++) = 0;
  388.  
  389.     else
  390.     p = _GP_NullString;
  391.  
  392. /* Continue recusive match */
  393.  
  394.     ReturnValue = _GP_ExpandField (file, p, gp);
  395.  
  396. /* Restore if necessary */
  397.  
  398.     if (p != _GP_NullString)
  399.        *(--p) = '/';
  400.  
  401.     return ReturnValue;
  402. }
  403.  
  404. /* Add an argument to the stack - file is assumed to be a array big enough
  405.  * for the file name + 2
  406.  */
  407.  
  408. static int    _GP_AddArgument (file, gp)
  409. char        *file;
  410. glob_t        *gp;
  411. {
  412.     int        Offset;
  413.     char    **p1;
  414.     struct stat    FileStatus;
  415.  
  416.     Offset = gp->gl_pathc + ((gp->gl_flags & GLOB_DOOFFS) ? gp->gl_offs : 0);
  417.     p1  = gp->gl_pathv;
  418.  
  419. /* Malloc space if necessary */
  420.  
  421.     if (gp->gl_pathc == 0)
  422.     p1 = (char **)calloc (sizeof (char *), (50 + Offset));
  423.  
  424.     else if ((gp->gl_pathc % 50) == 0)
  425.     p1 = (char **)realloc (p1, (Offset + 50) * (sizeof (char *)));
  426.  
  427.     if (p1 == (char **)NULL)
  428.     return GLOB_NOSPACE;
  429.  
  430. /* OK got space */
  431.  
  432.     gp->gl_pathv = p1;
  433.  
  434. /* End of list ? */
  435.  
  436.     if (file == (char *)NULL)
  437.     p1[Offset] = (char *)NULL;
  438.  
  439.     else
  440.     {
  441.     if ((gp->gl_flags & GLOB_MARK) && (file[strlen (file) - 1] != '/') &&
  442.         (stat (file, &FileStatus) == 0) && (S_ISDIR (FileStatus.st_mode)))
  443.         strcat (file, "/");
  444.  
  445.     if ((p1[Offset] = strdup (file)) == (char *)NULL)
  446.         return GLOB_NOSPACE;
  447.  
  448.     strcpy (p1[Offset], file);
  449.  
  450. /* Increment counter */
  451.  
  452.     ++(gp->gl_pathc);
  453.     }
  454.  
  455.     return 0;
  456. }
  457.  
  458. #ifdef MSDOS
  459. /* Check for multi_drive prefix */
  460.  
  461. static char    *_GP_CheckForMultipleDrives (prefix)
  462. char        *prefix;
  463. {
  464.     if (strlen (prefix) < 2)
  465.     return (char *)NULL;
  466.  
  467.     if (((*prefix == '*') || (*prefix == '?')) && (prefix[1] == ':'))
  468.     return prefix + 1;
  469.  
  470.     if (*prefix != '[')
  471.     return (char *)NULL;
  472.  
  473.     while (*prefix && (*prefix != ']'))
  474.     {
  475.     if ((*prefix == '\\') && (*(prefix + 1)))
  476.         ++prefix;
  477.  
  478.     ++prefix;
  479.     }
  480.  
  481.     return (*prefix && (*(prefix + 1) == ':')) ? prefix + 1 : (char *)NULL;
  482. }
  483.  
  484. /* Some OS/2 functions to emulate the DOS functions */
  485.  
  486. #ifdef OS2
  487. static void     _dos_getdrive (cdp)
  488. unsigned int    *cdp;
  489. {
  490.     USHORT    cdr;
  491.     ULONG    ndr;
  492.  
  493.     DosQCurDisk((PUSHORT)&cdr, (PULONG) &ndr);
  494.     *cdp = (unsigned int)cdr;
  495. }
  496.  
  497. static void     _dos_setdrive (cdr, ndp)
  498. unsigned int    cdr;
  499. unsigned int    *ndp;
  500. {
  501.     ULONG    ulDrives;
  502.     USHORT    usDisk;
  503.     int        i;
  504.  
  505.     DosSelectDisk ((USHORT)cdr);
  506.  
  507. /* Get the current disk and check that to see the number of drives */
  508.  
  509.     DosQCurDisk (&usDisk, &ulDrives);        /* gets current drive        */
  510.  
  511.     for (i = 25; (!(ulDrives & (1L << i))) && i >= 0; --i)
  512.     continue;
  513.  
  514.     *ndp = (unsigned int)(i + 1);
  515. }
  516. #endif
  517.  
  518. /* Return the number of floppy disks */
  519.  
  520. static    int    _GP_GetNumberofFloppyDrives ()
  521. {
  522. #ifdef OS2
  523.     BYTE    nflop = 1;
  524.     DosDevConfig (&nflop, DEVINFO_FLOPPY, 0);
  525.     return nflop;
  526. #else
  527.     return ((_bios_equiplist () & 0x00c0) >> 6) + 1;
  528. #endif
  529. }
  530. #endif
  531.  
  532. /*
  533.  * Pattern Matching function
  534.  */
  535.  
  536. static bool    _GP_MatchPattern (string, pattern)
  537. char        *string;        /* String to match                  */
  538. char        *pattern;        /* Pattern to match against         */
  539. {
  540.     register int    cur_s;        /* Current string character         */
  541.     register int    cur_p;        /* Current pattern character        */
  542.  
  543. /* Match string */
  544.  
  545.     while (cur_p = *(pattern++))
  546.     {
  547.     cur_s = *(string++);        /* Load current string character    */
  548.  
  549.         switch (cur_p)            /* Switch on pattern character      */
  550.         {
  551.             case '[':            /* Match class of characters        */
  552.             {
  553.                 while(1)
  554.                 {
  555.                     if (!(cur_p = *(pattern++)))
  556.             return 0;
  557.  
  558.                     if (cur_p == ']')
  559.             return FALSE;
  560.  
  561.                     if (cur_s != cur_p)
  562.                     {
  563.                         if (*pattern == '-')
  564.                         {
  565.                             if(cur_p > cur_s)
  566.                                 continue;
  567.  
  568.                             if (cur_s > *(++pattern))
  569.                                 continue;
  570.                         }
  571.                         else
  572.                             continue;
  573.                     }
  574.  
  575.                     break;
  576.                 }
  577.  
  578.                 while (*pattern)
  579.                 {
  580.                     if (*(pattern++) == ']')
  581.                         break;
  582.                 }
  583.  
  584.         break;
  585.             }
  586.  
  587.             case '?':            /* Match any character              */
  588.             {
  589.                 if (!cur_s)
  590.             return FALSE;
  591.  
  592.                 break;
  593.             }
  594.  
  595.             case '*':            /* Match any number of any character*/
  596.             {
  597.                 string--;
  598.  
  599.                 do
  600.                 {
  601.                     if (_GP_MatchPattern (string, pattern))
  602.             return TRUE;
  603.                 }
  604.                 while (*(string++));
  605.  
  606.         return FALSE;
  607.             }
  608.  
  609.             case '\\':            /* Next character is non-meta       */
  610.             {
  611.                 if (!(cur_p = *(pattern++)))
  612.             return FALSE;
  613.             }
  614.  
  615.             default:            /* Match against current pattern    */
  616.             {
  617.                 if (cur_p != cur_s)
  618.             return FALSE;
  619.  
  620.                 break;
  621.             }
  622.         }
  623.     }
  624.  
  625.     return (!*string) ? TRUE : FALSE;
  626. }
  627.  
  628. /*
  629.  * Test program
  630.  */
  631.  
  632. #ifdef TEST
  633. main (int argc, char **argv)
  634. {
  635.     int        i;
  636.  
  637.     for (i = 0; i < argc; i++)
  638.     printf ("Arg %d = <%s>\n", i, argv[i]);
  639. }
  640. #endif
  641.